<?php
/**
 * @author jonathan <jo.link.noir@gmail.com>
 * @version 1.0: jo_link_noir
 * @date 18-06-2010
 */
class U1_Confrontation
{
	/** @var U1_Units*/
	protected $attack, $defense;

	/** @var int*/
	protected $round;

	/** @var string*/
	protected $report;


	/**
	 * @param U1_Units $attack
	 * @param U1_Units $defense
	 * @param int $round = 10
	 */
	public function __construct(U1_Units $attack, U1_Units $defense, $round = 10)
	{
		$this->attack = $attack;
		$this->defense = $defense;
		$this->round = ($round > 0) ? (int)$round : 10;
	}

	/**
	 * @param U1_Units $attack
	 * @param U1_Units $defense
	 * @return mixed
	 */
	public function confrontation(U1_Units $attack, U1_Units $defense)
	{
		$damage1 = $damage2 = $round = 0;
		$this->beginningConfrontation();

		while ($round++ !== $this->round)
		{
			if ($this->attack->isEmpty())
				return $this->endAttack();
			else if ($this->defense->isEmpty())
				return $this->endDefense();

			$info1 = self::getInfoUnit($this->attack);
			$info2 = self::getInfoUnit($this->defense);
			$damage1 = self::lossProcess($this->attack, ($info2->attack + $damage1) / $info1->size);
			$damage2 = self::lossProcess($this->defense, ($info1->attack + $damage2) / $info2->size);
			$this->endOfTurn();
		}

		return $this->endConfrontation();
	}

	protected function beginningConfrontation()
	{
		$this->report = U1_Display_Army::getMessageRound(0, $this->attack, $this->defense);
	}

	/**
	 * @return string : rapport de combat
	 */
	protected function endAttack()
	{
		$this->report .= U1_Display_Army::getMessageConfrontationResult(true, $this->defense->isEmpty());
		return $this->report;
	}

	/**
	 * Si appeler alors il reste encore des attaquant mais plus de défense
	 * @return string : rapport de combat
	 */
	protected function endDefense()
	{
		$this->report .= U1_Display_Army::getMessageConfrontationResult(false, true);
		return $this->report;
	}

	protected function endOfTurn()
	{
		$this->report .= U1_Display_Army::getMessageRound($round, $this->attack, $this->defense);
	}

	/**
	 * @return string : rapport de combat
	 */
	protected function endConfrontation()
	{
		$this->report .= U1_Display_Army::getMessageConfrontationResult($this->attack->isEmpty(), $this->defense->isEmpty());
		return $this->report;
	}

	/**
	 * @param U1_Units $units
	 * @param int $coefAttack
	 * @return int : damage
	 */
	protected function lossProcess(U1_Units $units, $coefAttack)
	{
		//dégât restant à la fin du tour
		$damage = 0;
		foreach ($units as $group => $unit)
		{
			$count = $unit->getCount();
			$defense = $unit->stats[U1_Unit::STAT_STRUCTURE]
					+ $unit->stats[U1_Unit::STAT_DEFENSE]
					+ $unit->stats[U1_Unit::STAT_SHIED];
			$attack = $coefAttack * $unit->stats[U1_Unit::STAT_SIZE];
			$minDead = floor($attack - ($defense - 1) * $count);

			if ($count > $minDead)
			{
				if ($minDead < 0)
					$minDead = 0;

				$dead = floor($attack / $defense) - $minDead;
				if (.0 !== $dead)
					$dead = mt_rand(round($dead/1.2), $dead);
				$dead += $minDead;

				$damage += ($count > $dead)
					? $attack * $count - $defense * $dead
					: ($attack - $defense) * $count;

				$units->subtractUnit($group, $dead);
			}
			else
			{
				$units->offsetUnset($group);
				$damage += ($attack - $defense) * $count;
			}
		}
		return $damage;
	}

	/**
	 * @return StdClass : {'attack' => attaque totale, 'size' => taille totale}
	 */
	protected function getInfoUnit(U1_Units $units)
	{
		$o = new StdClass;
		$o->attack = $o->size = 0;

		foreach ($units as $unit)
		{
			$o->attack	+= $unit->getStat(U1_Unit::STAT_ATTACK);
			$o->size	+= $unit->getStat(U1_Unit::STAT_SIZE);
		}
		return $o;
	}
}